package edu.luc.cs.trull;

import edu.luc.cs.trull.swing.FastSwingScheduler;
import edu.luc.cs.trull.swing.SwingScheduler;

/**
 * A factory class that provides access to the available implementations
 * of the ComponentScheduler interface.  Trull applications that use Swing 
 * should invoke the setMode method to set the execution mode 
 * to SWINGFAST or SWINGTEST; this guarantees that the application
 * satisfies the Swing single-thread rule without explicit
 * scheduling of tasks in the Swing event dispatch thread.
 * @see edu.luc.cs.trull.DefaultScheduler 
 * @see edu.luc.cs.trull.FastScheduler 
 * @see edu.luc.cs.trull.swing.SwingScheduler 
 * @see edu.luc.cs.trull.swing.FastSwingScheduler 
 */
public class Scheduling {

  /**
   * A scheduler that supports await but executes more slowly.
   */
  public static final Class TEST = DefaultScheduler.class;

  /**
   * A scheduler that does not support await but executes faster.
   */
  public static final Class FAST = FastScheduler.class;

  /**
   * A scheduler for GUI applications that integrates with the Swing event thread..
   */
  public static final Class SWINGTEST = SwingScheduler.class;
    
  /**
   * A faster scheduler for GUI applications that does not support await.
   */
  public static final Class SWINGFAST = FastSwingScheduler.class;

  /**
   * The default scheduler is the fast non-GUI scheduler.
   */
  public static final Class DEFAULT = FAST;

  /**
   * The currently active scheduler class.
   */
  private static Class schedulerClass = DEFAULT;
    
  /**
   * Sets the current scheduling strategy according to the given scheduler class. 
   * @param schedulerClass the scheduler class to be used.
   * @throws IllegalArgumentException if the argument does not implement Scheduler.
   */
  public static synchronized void setMode(Class schedulerClass) {
    if (Scheduling.schedulerClass == schedulerClass) {
      return;
    }
    if (! Scheduler.class.isAssignableFrom(schedulerClass)) {
      throw new IllegalArgumentException("Argument class does not implement Scheduler");   
    }
	  Scheduling.schedulerClass = schedulerClass;
	  defaultInstance = null;
  }
  
  /**
   * The single instance of the current scheduler class.
   */
	private static ComponentScheduler defaultInstance = null;

  /**
   * Returns the current scheduler instance.
   * @return the current scheduler instance.
   */
	public static synchronized ComponentScheduler getScheduler() {
    try {
    		if (defaultInstance == null) {
    			defaultInstance = new ComponentSchedulerAdapter((Scheduler) schedulerClass.newInstance());
    		}
    		return defaultInstance;
    } catch (Exception e) {
      throw new RuntimeException(e);   
    }
	}
}